/****************************************Copyright (c)***************************************
---------------------------------------------------------------------------------------------
** Created by:          吴俊标  周 灵  王 宇  田明钲
** Last modified Date:  2024-12-24
** Descriptions:        STM32F407嵌入式实验教学箱
**-------------------------------------------------------------------------------------------*/

//********************************************************************************************/
#include "main.h"
#include "test.h"
#include "includes.h" // 添加UCOSIII头文件
#include <string.h> // 显式包含字符串处理函数

// 任务优先级定义
#define START_TASK_PRIO      3
#define KEY_SCAN_TASK_PRIO   4
#define LED_TASK_PRIO        5
#define HUMDETECT_TASK_PRIO  6
#define CURTAIN_TASK_PRIO    7
#define FAN_TASK_PRIO        8
#define WEATHER_TASK_PRIO    9

// 任务堆栈大小定义
#define START_STK_SIZE       256
#define KEY_SCAN_STK_SIZE    128
#define LED_STK_SIZE         128
#define HUMDETECT_STK_SIZE   128
#define CURTAIN_STK_SIZE     128
#define FAN_STK_SIZE         128
#define WEATHER_STK_SIZE     128

// 任务控制块
OS_TCB StartTaskTCB;
OS_TCB KeyScanTaskTCB;
OS_TCB LedTaskTCB;
OS_TCB HumDetectTaskTCB;
OS_TCB CurtainTaskTCB;
OS_TCB FanTaskTCB;
OS_TCB WeatherTaskTCB;

// 任务堆栈
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK KEY_SCAN_TASK_STK[KEY_SCAN_STK_SIZE];
CPU_STK LED_TASK_STK[LED_STK_SIZE];
CPU_STK HUMDETECT_TASK_STK[HUMDETECT_STK_SIZE];
CPU_STK CURTAIN_TASK_STK[CURTAIN_STK_SIZE];
CPU_STK FAN_TASK_STK[FAN_STK_SIZE];
CPU_STK WEATHER_TASK_STK[WEATHER_STK_SIZE];

// 信号量定义
OS_SEM LCD_SEM;       // LCD资源互斥信号量
OS_SEM HUMDETECT_SEM; // 人体检测信号量
OS_SEM KEY_SEM;       // 按键信号量 
OS_SEM TEMP_SEM;      // 温度数据信号量

// 全局变量定义
unsigned char startflag = 0;    // 风扇启动标志
unsigned short Speed = 0;       // 风扇速度
unsigned char Flag_1s = 0;      // 1秒标志

// 任务函数声明
void led_task(void *p_arg);
void humdetect_task(void *p_arg);
void curtain_task(void *p_arg);
void fan_task(void *p_arg);
void weather_task(void *p_arg);

// 计算字符串宽度（像素）
int calculate_string_width(const char* str) {
    int width = 0;
    while(*str) {
        if(*str > 0xa1) { // 中文字符
            width += 16;
            str += 2;
        } else { // ASCII字符
            width += 8;
            str += 1;
        }
    }
    return width;
}

// 计算居中显示的x坐标
int get_centered_x(const char* str) {
    int width = calculate_string_width(str);
    return (480 - width) / 2;
}

/*********************************************************************************************************
函数名称 : int main(void)
函数说明 : main函数
*********************************************************************************************************/

int main(void)
{ 
    SysTick_Init();           // 系统滴答定时器初始化
    LEDGpio_Init();           // LED引脚初始化
    KEYGpio_Init();           // 按键引脚初始化
    lcd_init();               // 液晶初始化

    // 初始化信号量
    LCD_SEM.Ctr = 1;          // LCD资源互斥信号量
    HUMDETECT_SEM.Ctr = 0;    // 人体检测信号量
    KEY_SEM.Ctr = 0;          // 按键信号量
    TEMP_SEM.Ctr = 0;         // 温度数据信号量

    // 直接按顺序调用各个模块的主要函数
    led_task(NULL);           // LED任务
    humdetect_task(NULL);     // 人体检测任务
    curtain_task(NULL);       // 窗帘控制任务
    fan_task(NULL);           // 风扇控制任务
    weather_task(NULL);       // 天气监测任务
    
    while(1); // 程序不应该到达这里
}

// LED灯控制任务（系统自检模块）
void led_task(void *p_arg)
{
    // 使用参数，避免警告
    p_arg = p_arg;
    
    lcd_clear(Black);
    LCD_DrawRectangle(0, 0, 479, 271, Green);
    LCD_DrawRectangle(5, 5, 474, 266, Green);
    
    // 居中显示标题
    LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, White, Black);    
    LCD_ShowString(get_centered_x(STR_AUTHOR_NAMES), 100, STR_AUTHOR_NAMES, Red, Black);     
    LCD_ShowString(get_centered_x(STR_WAITING), 220, STR_WAITING, White, Black);
                        
    LatticeGpio_Init(); // 点阵初始化
    
    // 直接进入LED灯跑马灯测试循环
    while(1)
    {
        HC595SendData(0x00, 0x00, 0xFF, 0xFF); // 全亮
        
        LED4_ON;
        LED3_OFF;
        LED2_OFF;
        LED1_OFF;
        delay_ms(100);
        
        LED4_OFF;
        LED3_ON;
        LED2_OFF;
        LED1_OFF;
        delay_ms(100);
        
        LED4_OFF;
        LED3_OFF;
        LED2_ON;
        LED1_OFF;
        delay_ms(100);
        
        LED4_OFF;
        LED3_OFF;
        LED2_OFF;
        LED1_ON;
        delay_ms(100);
        
        // 只检测S4按键，按下则进入下一个模块
        if (KeyScan() == 4)
        {
            return; // 立即进入下一个模块
        }
    }
}

// 人体检测任务
void humdetect_task(void *p_arg)
{
    unsigned char value1 = 0;
    
    // 使用参数，避免警告
    p_arg = p_arg;
    
    lcd_clear(Black);
    LCD_DrawRectangle(0, 0, 479, 271, Green);
    LCD_DrawRectangle(5, 5, 474, 266, Green);
    
    // 居中显示标题
    LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, White, Black);        
    LCD_ShowString(get_centered_x(STR_HUMAN_DETECT_TITLE), 100, STR_HUMAN_DETECT_TITLE, Red, Black);    
    
    HumIRGpio_Init(); // 人体红外引脚初始化
    
    while(1)
    {
        value1 = HUMIRIN();
        
        if(value1 == 1) // 检测到有人
        {
            LCD_ShowString(get_centered_x(STR_WELCOME_HOME), 180, STR_WELCOME_HOME, White, Black);
            DiplayChineseCharacters(); // 显示汉字
            delay_ms(2000); // 等待2秒确保显示完成
            return; // 返回main函数继续执行下一个任务
        }
        else
        {
            LCD_ShowString(get_centered_x(STR_WAITING_STATUS), 180, STR_WAITING_STATUS, White, Black);
        }
        
        delay_ms(100); // 每100ms检测一次
    }
}

// 窗帘控制任务
void curtain_task(void *p_arg)
{
    unsigned int date = 0;
    unsigned int temp = 0; 
    unsigned char Databuf[3] = {0};
    char Displaybuf[20] = {0};
    int lux;
    
    // 使用参数，避免警告
    p_arg = p_arg;
    
    lcd_clear(Black);
    LCD_DrawRectangle(0, 0, 479, 271, Green);
    LCD_DrawRectangle(5, 5, 474, 266, Green);
    LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, White, Black);        
    LCD_ShowString(get_centered_x(STR_CURTAIN_TITLE), 100, STR_CURTAIN_TITLE, Red, Black);    
    LCD_ShowString(get_centered_x(STR_CURRENT_LUX), 150, STR_CURRENT_LUX, Red, Black);
    LCD_ShowString(get_centered_x(STR_S3_NEXT), 225, STR_S3_NEXT, White, Black);
    
    I2C_GPIO_Configuration(); // 配置I2C的GPIO
    StepMotorGpio_Init();     // 初始化步进电机引脚
    BH1750_Init();            // 初始化BH1750
    
    while(1)
    {
        BH1750_ReadData(BH1750_SlaveAddress, Databuf);
        
        temp = Databuf[0];
        temp = (temp << 8) + Databuf[1];
        date = temp * 10 / 12;
        
        sprintf(Displaybuf, "%5u Lux", date);
        
        LCD_ShowString(300, 150, (unsigned char*)Displaybuf, White, Black);
        
        lux = atoi(Displaybuf);
        
        if(lux > 1000) // 光照过强，窗帘下拉
        {
            xiajiantou();
            LCD_ShowString(get_centered_x(STR_CURTAIN_DOWN), 200, STR_CURTAIN_DOWN, Red, Black);
            
            StepMotorTest(0);
        }
        else if(lux < 5) // 光照过弱，窗帘上拉
        {
            shangjiantou();
            LCD_ShowString(get_centered_x(STR_CURTAIN_UP), 200, STR_CURTAIN_UP, Red, Black);
            
            StepMotorTest(1);
        }
        else if(5 <= lux && lux <= 1000) // 光照正常，窗帘静止
        {
            LCD_ShowString(get_centered_x(STR_CURTAIN_STATIC), 200, STR_CURTAIN_STATIC, Red, Black);
        }
        
        // 检查是否按下S3按键
        if(KeyScan() == 3)
        {
            lcd_clear(Black);
            delay_ms(500);
            return; // 返回main函数继续执行下一个任务
        }
        
        delay_ms(500); // 每500ms检测一次
    }
}

// 风扇控制任务
void fan_task(void *p_arg)
{
    unsigned char temperature;          
    unsigned char humidity;     
    char buf[20] = "";
    long Databuf[2] = {0};
    char Dispbuf[50] = "";
    
    // 使用参数，避免警告
    p_arg = p_arg;
    
    lcd_clear(Black);
    LCD_DrawRectangle(0, 0, 479, 271, Green);
    LCD_DrawRectangle(5, 5, 474, 266, Green);
    
    // 居中显示标题
    LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, White, Black);       
    LCD_ShowString(get_centered_x(STR_FAN_TITLE), 100, STR_FAN_TITLE, Red, Black);    
    LCD_ShowString(get_centered_x(STR_S2_NEXT), 225, STR_S2_NEXT, White, Black);
    
    DCMotorGpio_Init();        // 初始化直流电机引脚
    I2C_GPIO_Configuration();   // I2C引脚配置
    InitBMP180();              // 初始化BMP085
    
    while(1)
    {
        DTH11_ReadData(&temperature, &humidity); // 读取温湿度值
        
        sprintf(buf, STR_TEMPERATURE, temperature);
        LCD_ShowString(get_centered_x(buf), 150, (unsigned char*)buf, Red, Black);
        
        // 只受温度控制
        if(temperature > 29) // 大于29度打开风扇
        {
            startflag = 1;
            LCD_ShowString(get_centered_x(STR_FAN_ON), 200, STR_FAN_ON, Red, Black);
        }
        else if(temperature < 28) // 小于28度关闭风扇
        {
            LCD_ShowString(get_centered_x(STR_FAN_OFF), 200, STR_FAN_OFF, Red, Black);
            startflag = 0;
            DCMOTOR_A_L;
            DCMOTOR_B_L;  
        }
        // 28~29度区间不做任何操作，风扇保持原状态
        
        if(Flag_1s == 1)
        {
            Speed = 0;
            Flag_1s = 0;
        }
        
        // 检查是否按下S2按键
        if(KeyScan() == 2)
        {
            lcd_clear(Black);
            delay_ms(500);
            startflag = 0;
            DCMOTOR_A_L;
            DCMOTOR_B_L;  
            return; // 返回main函数继续执行下一个任务
        }
        
        delay_ms(500); // 每500ms检测一次
    }
}

// 天气监测任务
void weather_task(void *p_arg)
{
    unsigned char temp = 0;
    
    // 使用参数，避免警告
    p_arg = p_arg;
    
    lcd_clear(Black);
    LCD_DrawRectangle(0, 0, 479, 271, Green);
    LCD_DrawRectangle(5, 5, 474, 266, Green);
    LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, White, Black);    
    LCD_ShowString(get_centered_x(STR_WEATHER_TITLE), 100, STR_WEATHER_TITLE, Red, Black);    
    LCD_ShowString(get_centered_x(STR_GREEN_SUNNY), 150, STR_GREEN_SUNNY, Green, Black); 
    LCD_ShowString(get_centered_x(STR_YELLOW_CLOUDY), 170, STR_YELLOW_CLOUDY, Yellow, Black); 
    LCD_ShowString(get_centered_x(STR_RED_RAINY), 190, STR_RED_RAINY, Red, Black); 
    
    TrafficLightGpio_Init();
    
    delay_ms(5000);
    
    lcd_clear(Black);
    
    while(1)
    {
        temp = TrafficLight_Run();
        
        // 检查是否按下S1按键
        if(KeyScan() == 1)
        {
            lcd_clear(Black);
            delay_ms(500);
            
            // 显示结束界面
            lcd_clear(Black);
            LEDY_NS_OFF;
            LEDY_EW_OFF;
            LEDR_NS_OFF;
            LEDR_EW_OFF;
            LEDG_NS_OFF;
            LEDG_EW_OFF;
            LCD_DrawRectangle(0, 0, 479, 271, Green);
            LCD_DrawRectangle(5, 5, 474, 266, Green);  
            LCD_ShowString(get_centered_x(STR_SMART_HOME), 50, STR_SMART_HOME, Red, Black);             
            LCD_ShowString(get_centered_x(STR_GOODBYE), 150, STR_GOODBYE, White, Black); 
            
            // 程序结束
            while(1) {
                // 无限循环，程序结束
                delay_ms(1000);
            }
        }
        
        delay_ms(100); // 每100ms检测一次
    }
}